package com.km.app.controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: eric
 * Date: 2017-11-23
 * Time: 14:15
 */

import com.km.app.controller.param.*;
import com.km.app.domain.R;
import com.km.app.domain.po.SysFile;
import com.km.app.domain.vo.FileVO;
import com.km.app.service.FileService;
import com.km.app.util.FileDigest;
import com.km.app.util.FileUtil;
import com.km.app.util.IdGen;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

@Api(description = "文件操作接口")
@RestController
public class FileController {

    private final static Log log = LogFactory.getLog(FileController.class);

    @Value("${spring.http.upload.base.path}")
    private String basePath;

    @Autowired
    private FileService fileService;

    public String getContentType(String filename) {
        String type = "";
        Path path = Paths.get(filename);
        try {
            type = Files.probeContentType(path);
        } catch (IOException e) {
            log.error(e);
        }
        return type;
    }

    @ApiOperation(value = "文件下载", notes = "" +
            "<div>文件直接下载或者图片显示,直接访问地址： http://{service}:{port}/{project}/file/{appId}/{path}/{name}</div>" +
            "<div>&nbsp;</div>"+
            "<div>访问示例</div>"+
            "<div>显示图片：http://{service}:{port}/{project}/file/{appid}/test/test.jpg</div>"+
            "<div>下载文件：http://{service}:{port}/{project}/file/{appid}/test/test.excel</div>"+
            "<div>&nbsp;</div>"+
            "<div>参数示例</div>"+
            "<div>缩放图片：http://{service}:{port}/{project}/file/{appid}/test/test.jpg?process=image/resize,width_300,height_300</div>"+
            "<div>切割图片：http://{service}:{port}/{project}/file/{appid}/test/test.jpg?process=image/crop,startX_300,startY_300,endX_300,endY_300</div>"+
            "<div>切割并缩放：http://{service}:{port}/{project}/file/{appid}/test/test.jpg?process=image/cropAndResize,width_300,height_300</div>"+
            "<div>下载图片：http://{service}:{port}/{project}/file/{appid}/test/test.jpg?process=image/download</div>"+
            "<div>下载文件：http://{service}:{port}/{project}/file/{appid}/test/test.jpg?process=file/download</div>"
    )
    @RequestMapping(value = "/file/**", method = RequestMethod.GET)
    public void file(
            @ApiParam(value = "request", hidden = true) HttpServletRequest request,
            @ApiParam(value = "response", hidden = true) HttpServletResponse response,
            @ApiParam(value = "查询字符串",hidden = false) @RequestParam(required = false) String process
    ) throws Exception {
        String path = request.getServletPath();
        String fullPath = path.substring("/file/".length(), path.length());
        R r = new R();
        if (StringUtils.isBlank(fullPath)) {
            throw new Exception("文件路径格式错误");
        }
        SysFile sysFile = fileService.queryByVirtualPath(fullPath);
        if (sysFile == null) {
            throw new Exception("文件不存在");
        }
        String realPath = basePath + sysFile.getPath();
        int i = fullPath.lastIndexOf("/");
        if (i == -1) {
            throw new Exception("文件路径格式错误");
        }
        File file = new File(realPath);
        if (!file.exists()) {
            throw new Exception("文件不存在");
        }
        String fileName = fullPath.substring(i + 1);
        ParamContext context = new ParamContext(process);
        context.add("image/resize", new ResizeState(realPath));
        context.add("image/crop", new CropState(realPath));
        context.add("image/cropAndResize", new ResizeAndCropState(realPath));
        context.add("image/download", new DownloadState(realPath));
        context.add("file/download", new DownloadState(realPath));
        context.excute(realPath, fileName, request, response);
    }


    //文件上传相关代码
    @ApiOperation(value = "单文件上传", notes = "" +
            "appId：需要先向提供方申请，用作身份识别用。" +
            "path：文件目录由您提供给系统，文件读取时需要用到。（可不传，系统不作处理）。" +
            "name：文件名称由您提供给系统（重复做覆盖操作），文件读取时需要用到。（可不传，系统生成）。" +
            "返回的fullPath格式 {appId}/{path}/{name}" +
            "文件读取示例 http://{service}:{port}/{project}/file/{appId}/{path}/{name}。" +
            "你也可以使用 http://{service}:{port}/{project}/file/{fullPath}。")
    @PostMapping(value = "/upload")
    @ResponseBody
    @Transactional
    public R<FileVO> upload(
            @ApiParam(value = "文件", required = true) @RequestParam("file") MultipartFile file,
            @ApiParam(value = "appId", required = true) @RequestParam(defaultValue = "100") String appId,
            @ApiParam(value = "文件目录 例如 user/head/", required = true) @RequestParam(defaultValue = "") String path,
            @ApiParam(value = "文件名称 例如 uuid.jpg", required = true) @RequestParam(defaultValue = "") String name
    ) throws UnsupportedEncodingException {
        R r = new R();
        if (file.isEmpty()) {
            return r.fail().setMessage("文件为空");
        }
        String fileName = file.getOriginalFilename(); // 获取文件名
        String suffixName = "";
        if (fileName.contains(".")) {
            suffixName = fileName.substring(fileName.lastIndexOf("."));// 获取文件的后缀名
        }
        String timeDirectory = FileUtil.timeDirectory();
        String id = IdGen.uuid();
        //path = StringUtils.isBlank(path) ? timeDirectory : path;
        name = StringUtils.isBlank(name) ? (id + suffixName) : name;
        String virtualPath = appId + "/" + path + "/" + name;//文件虚拟路径 请求示例  http://{host}:{port}/{file}/{appId}/{path}/{name}
        virtualPath = virtualPath.replaceAll("//", "/");
        String directoryId = fileService.saveVirtualPath(appId, path);//保存虚拟目录
        //保存文件
        String md5 = FileDigest.getFileMD5(file);//文件字节转成md5,校验重复文件
        SysFile sysFile = fileService.queryByMd5(md5);
        //根据虚拟路径删除先前的信息（做覆盖操作）
        fileService.deleteExistVirtualPathData(virtualPath);
        long size = file.getSize(); //获取文件大小
        //重复上传直接使用以前的
        if (sysFile != null) {
            System.out.println("重复文件直接返回");
            int ret = fileService.saveFile(id, appId, directoryId, name, size, sysFile.getPath(), virtualPath, md5);//创建虚拟目录
            if (ret > 0) {
                FileVO vo = new FileVO(sysFile.getId(), appId, name, path, size);
                return r.success().setData(vo).setMessage("上传成功");
            } else {
                throw new RuntimeException("数据保存失败");
                //return r.setCodeMessage(100, "数据保存失败");
            }
        }
        //保存新文件
        String newFileName = id + suffixName;//新文件名
        String relativePath = timeDirectory + "/" + newFileName;//文件上传手的相对路径
        String realPath = basePath + relativePath;// 文件上传后的绝对路径
        File dest = new File(realPath);
        if (!dest.getParentFile().exists()) {// 检测是否存在目录
            dest.getParentFile().mkdirs();
        }
        try {
            file.transferTo(dest);
            int ret = fileService.saveFile(id, appId, directoryId, name, size, relativePath, virtualPath, md5);//创建虚拟目录
            if (ret > 0) {
                FileVO vo = new FileVO(id, appId, name, path, size);
                return r.success().setData(vo).setMessage("上传成功");
            } else {
                throw new RuntimeException("数据保存失败");
                //return r.setCodeMessage(100,"数据保存失败失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("数据保存失败");
            //return r.setCodeMessage(100,"上传失败");
        }
    }

    //多文件上传
    @ApiOperation(value = "多文件上传", hidden = true)
    @PostMapping(value = "/batch/upload")
    @ResponseBody
    @Transactional
    public R<List<FileVO>> handleFileUpload(
            HttpServletRequest request,
            @ApiParam(value = "appId", required = true) @RequestParam(defaultValue = "100") String appId,
            @ApiParam(value = "文件路径 例如 user/head", required = true) @RequestParam(defaultValue = "") String path
    ) {
        R r = new R();
        List<FileVO> list = new ArrayList<>();
        List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
        MultipartFile file = null;
        BufferedOutputStream stream = null;
        for (int i = 0; i < files.size(); ++i) {
            file = files.get(i);
            if (!file.isEmpty()) {
                //逻辑同单文件上传
            }
        }
        r.setData(list);
        return r.success().setMessage("上传成功");
    }

}